package com.nit.netty.bean.invoker;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.nit.netty.model.Request;
import com.nit.netty.model.Response;
import com.nit.netty.sender.RequestSender;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Map;
import java.util.UUID;

/**
 * @Author: whb
 * @Description:
 * @CreateTime: 2020/8/21 10:16
 */
public class NettyInterfaceInvoker implements InvocationHandler {

    private RequestSender sender;

    /**
    * @Description: 单例模式
    */
    private static class SINGLETON {
        private static final NettyInterfaceInvoker invoker = new NettyInterfaceInvoker();

        private static NettyInterfaceInvoker setSender(RequestSender sender) {
            invoker.sender = sender;
            return invoker;
        }
    }

    public static NettyInterfaceInvoker getInstance() {
        return SINGLETON.invoker;
    }

    public static NettyInterfaceInvoker setSender(RequestSender sender) {
        return SINGLETON.setSender(sender);
    }

    /**
    * @Description: 在FactoryBean中的getObject方法中的invoker类是该类, 所以该工厂生成的bean都会被该invoke方法代理
     * 这里完成了我们的基本模型, client调用service, 通过代理走netty通信调用服务端的实现类
    */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Request request = new Request();
        request.setClassName(method.getDeclaringClass().getName());
        request.setMethodName(method.getName());
        request.setParameters(args);
        request.setParameterTypes(method.getParameterTypes());
        // 线程特有的id, 多个线程访问一个channel的时候需要使用id判断
        request.setId(UUID.randomUUID().toString());
        // 通过netty去调用真正的服务, 获得回传
        Object result = sender.send(request);
        Class<?> returnType = method.getReturnType();

        Response response = JSON.parseObject(result.toString(), Response.class);
        if (response.getCode() == 502) {
            throw new Exception(response.getError());
        }
        // 根据method的返回值处理response
        if (returnType.isPrimitive() || String.class.isAssignableFrom(returnType)) {
            return response.getData();
        } else if (Collection.class.isAssignableFrom(returnType)) {
            return JSONArray.parseArray(response.getData().toString(), Object.class);
        } else if (Map.class.isAssignableFrom(returnType)) {
            return JSON.parseObject(response.getData().toString(), Map.class);
        } else {
            Object data = response.getData();
            return JSONObject.parseObject(data.toString(), returnType);
        }
    }
}
